package com.dlc.shop.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.BooleanUtil;
import cn.hutool.core.util.IdUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.dlc.shop.bean.dto.UploadSuccessDTO;
import com.dlc.shop.bean.model.AttachFile;
import com.dlc.shop.bean.model.AttachFileGroup;
import com.dlc.shop.bean.vo.PreSignUrlVO;
import com.dlc.shop.common.config.Constant;
import com.dlc.shop.common.exception.YamiShopBindException;
import com.dlc.shop.common.i18n.I18nMessage;
import com.dlc.shop.common.util.PageParam;
import com.dlc.shop.config.AwsS3Config;
import com.dlc.shop.dao.AttachFileMapper;
import com.dlc.shop.service.AttachFileGroupService;
import com.dlc.shop.service.AttachFileService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Objects;

/**
 * @author lgh
 * @date 2018/07/27
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class AttachFileServiceImpl extends ServiceImpl<AttachFileMapper, AttachFile> implements AttachFileService {

    @Value("${yami.expose.operation.auth:}")
    private Boolean permission;

    private final AttachFileMapper attachFileMapper;
    private final AttachFileGroupService attachFileGroupService;
    private final AwsS3Config awsS3Config;

    public final static String NORM_MONTH_PATTERN = "yyyy/MM/";

    @Override
    @Transactional(rollbackFor = Exception.class)
    public String uploadFile(byte[] bytes, String originalName) throws IOException {
        String extName = FileUtil.extName(originalName);
        String imgName = FileUtil.mainName(originalName);
        String filePath = randomFilePath(extName);
        AttachFile attachFile = new AttachFile();
        attachFile.setFilePath(filePath);
        attachFile.setFileSize(bytes.length);
        attachFile.setFileType(extName);
        attachFile.setFileName(imgName);
        attachFile.setUploadTime(new Date());
        attachFileMapper.insert(attachFile);
        awsS3Config.uploadFile(filePath, bytes);
        return filePath;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteByIdsAndShopId(List<Long> ids, Long shopId) {
        if (BooleanUtil.isFalse(permission)) {
            throw new YamiShopBindException("yami.no.auth");
        }
        List<AttachFile> attachFileList = attachFileMapper.getByIds(ids);
        // 获取文件的实际路径--数据库中保存的文件路径为： / + 实际的文件路径
        List<String> filePaths = attachFileList.stream().map(item -> {
            if (!Objects.equals(item.getShopId(), shopId)) {
                throw new YamiShopBindException("存在非本店铺下的文件，删除失败");
            }
            return item.getFilePath();
        }).toList();
        //图片添加也是循环添加，批量删除目前也是循环单个删除，后续或许有更好的办法
        awsS3Config.deleteBatchFile(filePaths);
        attachFileMapper.batchDeleteByIds(ids);
    }

    @Override
    public void batchMoveByShopIdAndIdsAndGroupId(Long shopId, AttachFile attachFile) {
        if (CollUtil.isEmpty(attachFile.getFileIds())) {
            throw new YamiShopBindException("文件id列表不能为空");
        }
        Long attachFileGroupId = attachFile.getAttachFileGroupId();
        if (Objects.nonNull(attachFileGroupId)) {
            AttachFileGroup attachFileGroup = attachFileGroupService.getByAttachFileGroupId(attachFileGroupId);
            if (Objects.isNull(attachFileGroup)) {
                throw new YamiShopBindException("当前分组已不存在，请刷新后重试");
            }
            if (!Objects.equals(attachFileGroup.getShopId(), shopId)) {
                throw new YamiShopBindException("yami.no.auth");
            }
        } else {
            attachFileGroupId = 0L;
        }

        attachFileMapper.batchMoveByShopIdAndIdsAndGroupId(shopId, attachFile.getFileIds(), attachFileGroupId);
    }

    @Override
    public String getfileTypeByfilePath(String filePath) {
        return attachFileMapper.getfileTypeByfilePath(filePath);
    }

    private String randomFilePath(String fileType) {
        return DateUtil.format(new Date(), NORM_MONTH_PATTERN) + IdUtil.simpleUUID() + "." + fileType;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteFile(String filePath) {
        if (BooleanUtil.isFalse(permission)) {
            throw new YamiShopBindException("yami.no.auth");
        }
        attachFileMapper.delete(new LambdaQueryWrapper<AttachFile>().eq(AttachFile::getFilePath, filePath));
        awsS3Config.deleteFile(filePath);
    }

    @Override
    public Boolean updateFile(AttachFile attachFile) {
        return attachFileMapper.updateFile(attachFile);
    }

    @Override
    public IPage<AttachFile> getPage(PageParam<AttachFile> page, AttachFile attachFile) {
        return attachFileMapper.getPage(page, attachFile);
    }

    @Override
    public PreSignUrlVO getPreSingUrl(Long shopId, String fileName, Boolean isImFile) {
        this.checkFileName(fileName);
        // 构建文件类
        AttachFile attachFile = this.buildAttachFile(shopId, fileName, isImFile);
        // 生成预签名url
        String preSignUrl = awsS3Config.getPreSignUrl(attachFile.getFilePath());
        // 插入数据库（url生成成功后再插入）
        attachFileMapper.insert(attachFile);
        // 返回信息
        PreSignUrlVO preSignUrlVO = new PreSignUrlVO();
        preSignUrlVO.setOriFileName(fileName);
        preSignUrlVO.setFileId(attachFile.getFileId());
        preSignUrlVO.setFilePath(attachFile.getFilePath());
        preSignUrlVO.setPreSignUrl(preSignUrl);
        return preSignUrlVO;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public List<PreSignUrlVO> getBatchPreSignUrl(Long shopId, List<String> fileNames, Boolean isImFile) {
        if (CollectionUtils.isEmpty(fileNames)) {
            return new ArrayList<>();
        }
        // 构建文件类集合
        List<AttachFile> attachFiles = new ArrayList<>(fileNames.size());
        List<String> filePaths = new ArrayList<>(fileNames.size());
        AttachFile attachFile;
        for (String fileName : fileNames) {
            this.checkFileName(fileName);
            attachFile = this.buildAttachFile(shopId, fileName, isImFile);
            attachFiles.add(attachFile);
            filePaths.add(attachFile.getFilePath());
        }
        // 批量生成预签名url
        List<String> preSignUrls = awsS3Config.getBatchPreSignUrl(filePaths);
        // 批量插入数据库（url生成成功后再插入）
        this.saveBatch(attachFiles);
        // 返回消息
        List<PreSignUrlVO> preSignUrlVOList= new ArrayList<>(fileNames.size());
        PreSignUrlVO preSignUrlVO;
        for (int i=0; i<fileNames.size(); i++) {
            preSignUrlVO = new PreSignUrlVO();
            preSignUrlVO.setOriFileName(fileNames.get(i));
            preSignUrlVO.setFileId(attachFiles.get(i).getFileId());
            preSignUrlVO.setFilePath(attachFiles.get(i).getFilePath());
            preSignUrlVO.setPreSignUrl(preSignUrls.get(i));
            preSignUrlVOList.add(preSignUrlVO);
        }
        return preSignUrlVOList;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void uploadSuccess(List<UploadSuccessDTO> uploadSuccessDTOList) {
        if (CollectionUtils.isEmpty(uploadSuccessDTOList)) {
            return;
        }
        List<AttachFile> attachFiles = new ArrayList<>(uploadSuccessDTOList.size());
        AttachFile attachFile;
        for (UploadSuccessDTO uploadSuccessDTO : uploadSuccessDTOList) {
            attachFile = new AttachFile();
            BeanUtils.copyProperties(uploadSuccessDTO, attachFile);
            attachFile.setUploadTime(new Date());
            attachFile.setIsUpload(1);
            attachFiles.add(attachFile);
        }
        this.updateBatchById(attachFiles);
    }

    /**
     * 构建附件对象
     * @param shopId 店铺id
     * @param fileName 文件名
     * @param isImFile 是否为客服聊天对象
     * @return 附件对象
     */
    private AttachFile buildAttachFile(Long shopId, String fileName, Boolean isImFile) {
        AttachFile attachFile = new AttachFile();
        attachFile.setShopId(shopId);
        String extName = FileUtil.extName(fileName);
        attachFile.setFileType(extName);
        attachFile.setFilePath(randomFilePath(extName));
        attachFile.setFileName(FileUtil.mainName(fileName));
        attachFile.setUploadTime(new Date());
        attachFile.setIsUpload(0);
        if (BooleanUtil.isTrue(isImFile)) {
            // 客服聊天文件用'im'文件夹装起来
            attachFile.setFilePath("im/" + attachFile.getFilePath());
        }
        return attachFile;
    }

    /**
     * 校验文件名
     * @param fileName 文件名
     */
    private void checkFileName(String fileName) {
        // 只允许特定文件后缀名上传
        String extName = FileUtil.extName(fileName).toLowerCase();
        if (ObjectUtils.isEmpty(extName) ||
                !Constant.FILE_SUFFIX_NAMES.contains(extName)) {
            throw new YamiShopBindException(String.format(I18nMessage.getMessage("yami.upload.filename.forbid"), extName));
        }
    }
}
